

<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  
  <title>Basic Workflow &mdash; Ceph Documentation</title>
  

  
  <link rel="stylesheet" href="../../../_static/ceph.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/ceph.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/graphviz.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/css/custom.css" type="text/css" />

  
  

  
  

  

  
  <!--[if lt IE 9]>
    <script src="../../../_static/js/html5shiv.min.js"></script>
  <![endif]-->
  
    
      <script type="text/javascript" id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
        <script src="../../../_static/jquery.js"></script>
        <script src="../../../_static/_sphinx_javascript_frameworks_compat.js"></script>
        <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
        <script src="../../../_static/doctools.js"></script>
        <script src="../../../_static/sphinx_highlight.js"></script>
    
    <script type="text/javascript" src="../../../_static/js/theme.js"></script>

    
    <link rel="index" title="Index" href="../../../genindex/" />
    <link rel="search" title="Search" href="../../../search/" />
    <link rel="next" title="测试 - 单元测试" href="../tests-unit-tests/" />
    <link rel="prev" title="问题跟踪" href="../issue-tracker/" /> 
</head>

<body class="wy-body-for-nav">

   
  <header class="top-bar">
    <div role="navigation" aria-label="Page navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="../../../" class="icon icon-home" aria-label="Home"></a></li>
          <li class="breadcrumb-item"><a href="../">向 Ceph 贡献：开发者指南</a></li>
      <li class="breadcrumb-item active">Basic Workflow</li>
      <li class="wy-breadcrumbs-aside">
            <a href="../../../_sources/dev/developer_guide/basic-workflow.rst.txt" rel="nofollow"> View page source</a>
      </li>
  </ul>
  <hr/>
</div>
  </header>
  <div class="wy-grid-for-nav">
    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search"  style="background: #eee" >
          

          
            <a href="../../../" class="icon icon-home"> Ceph
          

          
          </a>

          

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../../../search/" method="get">
    <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

          
        </div>

        
        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
              
            
            
              <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../../start/">Ceph 简介</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../install/">安装 Ceph</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../cephadm/">Cephadm</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../rados/">Ceph 存储集群</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../cephfs/">Ceph 文件系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../rbd/">Ceph 块设备</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../radosgw/">Ceph 对象网关</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../mgr/">Ceph 管理器守护进程</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../mgr/dashboard/">Ceph 仪表盘</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../monitoring/">监控概览</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../api/">API 文档</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../architecture/">体系结构</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../">开发者指南</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../intro/">简介</a></li>
<li class="toctree-l2"><a class="reference internal" href="../essentials/">必备知识</a></li>
<li class="toctree-l2"><a class="reference internal" href="../merging/">何时、合并了什么</a></li>
<li class="toctree-l2"><a class="reference internal" href="../issue-tracker/">问题追踪器</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">基本工作流</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#updating-the-tracker">Updating the tracker</a></li>
<li class="toctree-l3"><a class="reference internal" href="#ceph-workflow-overview">Ceph Workflow Overview</a></li>
<li class="toctree-l3"><a class="reference internal" href="#preparing-your-local-working-copy-of-the-ceph-repository">Preparing Your Local Working Copy of the Ceph Repository</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#creating-a-fork-of-the-ceph-repository">Creating a Fork of the Ceph Repository</a></li>
<li class="toctree-l4"><a class="reference internal" href="#cloning-your-fork">Cloning Your Fork</a></li>
<li class="toctree-l4"><a class="reference internal" href="#configuring-your-local-environment">Configuring Your Local Environment</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#fixing-the-bug">Fixing the Bug</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#synchronizing-local-main-with-upstream-main">Synchronizing Local Main with Upstream Main</a></li>
<li class="toctree-l4"><a class="reference internal" href="#creating-a-bugfix-branch">Creating a Bugfix branch</a></li>
<li class="toctree-l4"><a class="reference internal" href="#fixing-the-bug-in-the-local-working-copy">Fixing the bug in the local working copy</a></li>
<li class="toctree-l4"><a class="reference internal" href="#pushing-the-fix-to-your-fork">Pushing the Fix to Your Fork</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#opening-a-github-pull-request">Opening a GitHub pull request</a></li>
<li class="toctree-l3"><a class="reference internal" href="#understanding-automated-pr-validation">Understanding Automated PR validation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#notes-on-pr-make-check-test">Notes on PR make check test</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#integration-tests-aka-ceph-qa-suite">Integration tests AKA ceph-qa-suite</a></li>
<li class="toctree-l3"><a class="reference internal" href="#code-review">Code review</a></li>
<li class="toctree-l3"><a class="reference internal" href="#amending-your-pr">Amending your PR</a></li>
<li class="toctree-l3"><a class="reference internal" href="#merging">Merging</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#proper-merge-commit-format">Proper Merge Commit Format</a></li>
<li class="toctree-l4"><a class="reference internal" href="#using-a-browser-extension-to-auto-fill-the-merge-message">Using a browser extension to auto-fill the merge message</a></li>
<li class="toctree-l4"><a class="reference internal" href="#using-githubmap-to-find-a-reviewer-s-email-address">Using .githubmap to Find a Reviewer’s Email Address</a></li>
<li class="toctree-l4"><a class="reference internal" href="#using-git-log-to-find-a-reviewer-s-email-address">Using “git log” to find a Reviewer’s Email Address</a></li>
<li class="toctree-l4"><a class="reference internal" href="#using-ptl-tool-to-generate-merge-commits">Using ptl-tool to Generate Merge Commits</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#miscellaneous">Miscellaneous</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#set-upstream">--set-upstream</a></li>
<li class="toctree-l4"><a class="reference internal" href="#deleting-a-branch-locally">Deleting a Branch Locally</a></li>
<li class="toctree-l4"><a class="reference internal" href="#deleting-a-branch-remotely">Deleting a Branch Remotely</a></li>
<li class="toctree-l4"><a class="reference internal" href="#searching-a-file-longitudinally-for-a-string">Searching a File Longitudinally for a String</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../tests-unit-tests/">测试：单元测试</a></li>
<li class="toctree-l2"><a class="reference internal" href="../testing_integration_tests/">测试：集成测试(Teuthology)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../running-tests-locally/">测试：在本地运行测试</a></li>
<li class="toctree-l2"><a class="reference internal" href="../tests-windows/">测试: Windows</a></li>
<li class="toctree-l2"><a class="reference internal" href="../dash-devel/">Ceph Dashboard 开发者文档 (之前是 HACKING.rst)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../jaegertracing/">Tracing 开发者文档</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../cephadm/">Cephadm 开发者文档</a></li>
<li class="toctree-l2"><a class="reference internal" href="../debugging-gdb/">用 GDB 调试</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../internals/">Ceph 内幕</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../governance/">项目管理</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../foundation/">Ceph 基金会</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../ceph-volume/">ceph-volume</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../releases/general/">Ceph 版本（总目录）</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../releases/">Ceph 版本（索引）</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../security/">Security</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../hardware-monitoring/">硬件监控</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../glossary/">Ceph 术语</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../jaegertracing/">Tracing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../translation_cn/">中文版翻译资源</a></li>
</ul>

            
          
        </div>
        
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" aria-label="top navigation">
        
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="../../../">Ceph</a>
        
      </nav>


      <div class="wy-nav-content">
        
        <div class="rst-content">
        
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
<div id="dev-warning" class="admonition note">
  <p class="first admonition-title">Notice</p>
  <p class="last">This document is for a development version of Ceph.</p>
</div>
  <div id="docubetter" align="right" style="padding: 5px; font-weight: bold;">
    <a href="https://pad.ceph.com/p/Report_Documentation_Bugs">Report a Documentation Bug</a>
  </div>

  
  <section id="basic-workflow">
<span id="basic-workflow-dev-guide"></span><h1>Basic Workflow<a class="headerlink" href="#basic-workflow" title="Permalink to this heading"></a></h1>
<p>The following chart illustrates the basic Ceph development workflow:</p>
<p class="ditaa">
<img src="../../../_images/ditaa-8f4afdd64de94de496909c837b163b57df5f07ad.png"/>
</p>
<p>This page assumes that you are a new contributor with an idea for a bugfix or
an enhancement, but you do not know how to proceed. Watch the <a class="reference external" href="https://www.youtube.com/watch?v=t5UIehZ1oLs">Getting Started
with Ceph Development</a> video (1
hour 15 minutes) for a practical summary of this workflow.</p>
<section id="updating-the-tracker">
<h2>Updating the tracker<a class="headerlink" href="#updating-the-tracker" title="Permalink to this heading"></a></h2>
<p>Find the <a class="reference internal" href="../issue-tracker/#issue-tracker"><span class="std std-ref">问题跟踪</span></a> (Redmine) number of the bug you intend to fix. If
no tracker issue exists, create one. There is only one case in which you do not
have to create a Redmine tracker issue: the case of minor documentation changes.</p>
<p>Simple documentation cleanup does not require a corresponding tracker issue.
Major documentation changes do require a tracker issue. Major documentation
changes include adding new documentation chapters or files, and making
substantial changes to the structure or content of the documentation.</p>
<p>A (Redmine) tracker ticket explains the issue (bug) to other Ceph developers to
keep them informed as the bug nears resolution. Provide a useful, clear title
and include detailed information in the description. When composing the title
of the ticket, ask yourself “If I need to search for this ticket two years from
now, which keywords am I likely to search for?” Then include those keywords in
the title.</p>
<p>If your tracker permissions are elevated, assign the bug to yourself by setting
the <code class="docutils literal notranslate"><span class="pre">Assignee</span></code> field. If your tracker permissions have not been elevated,
just add a comment with a short message that says “I am working on this issue”.</p>
</section>
<section id="ceph-workflow-overview">
<h2>Ceph Workflow Overview<a class="headerlink" href="#ceph-workflow-overview" title="Permalink to this heading"></a></h2>
<p>Three repositories are involved in the Ceph workflow. They are:</p>
<ol class="arabic simple">
<li><p>The upstream repository (<code class="docutils literal notranslate"><span class="pre">ceph/ceph</span></code>)</p></li>
<li><p>Your fork of the upstream repository (<code class="docutils literal notranslate"><span class="pre">your_github_id/ceph</span></code>)</p></li>
<li><p>Your local working copy of the repository (on your workstation)</p></li>
</ol>
<p>The procedure for making changes to the Ceph repository is as follows:</p>
<ol class="arabic simple">
<li><p>Configure your local environment</p>
<ol class="arabic simple">
<li><p><a class="reference internal" href="#forking"><span class="std std-ref">Create a fork</span></a> of the “upstream Ceph”
repository.</p></li>
<li><p><a class="reference internal" href="#cloning"><span class="std std-ref">Clone the fork</span></a> to your local filesystem.</p></li>
</ol>
</li>
<li><p>Fix the bug</p>
<ol class="arabic simple">
<li><p><a class="reference internal" href="#synchronizing"><span class="std std-ref">Synchronize local main with upstream main</span></a>.</p></li>
<li><p><a class="reference internal" href="#bugfix-branch"><span class="std std-ref">Create a bugfix branch</span></a> in your local working copy.</p></li>
<li><p><a class="reference internal" href="#fixing-bug-locally"><span class="std std-ref">Make alterations to the local working copy of the repository in your
local filesystem</span></a>.</p></li>
<li><p><a class="reference internal" href="#push-changes"><span class="std std-ref">Push the changes in your local working copy to your fork</span></a>.</p></li>
</ol>
</li>
<li><p>Create a Pull Request to push the change upstream.</p>
<ol class="arabic simple">
<li><p>Create a Pull Request that asks for your changes to be added into the
“upstream Ceph” repository.</p></li>
</ol>
</li>
</ol>
</section>
<section id="preparing-your-local-working-copy-of-the-ceph-repository">
<h2>Preparing Your Local Working Copy of the Ceph Repository<a class="headerlink" href="#preparing-your-local-working-copy-of-the-ceph-repository" title="Permalink to this heading"></a></h2>
<p>The procedures in this section, “Preparing Your Local Working Copy of the Ceph
Repository”, must be followed only when you are first setting up your local
environment. If this is your first time working with the Ceph project, then
these commands are necessary and are the first commands that you should run.</p>
<section id="creating-a-fork-of-the-ceph-repository">
<span id="forking"></span><h3>Creating a Fork of the Ceph Repository<a class="headerlink" href="#creating-a-fork-of-the-ceph-repository" title="Permalink to this heading"></a></h3>
<p>See the <a class="reference external" href="https://help.github.com/articles/fork-a-repo/#platform-linux">GitHub documentation</a> for
detailed instructions on forking. In short, if your GitHub username is
“mygithubaccount”, your fork of the upstream repo will appear at
<code class="docutils literal notranslate"><span class="pre">https://github.com/mygithubaccount/ceph</span></code>.</p>
</section>
<section id="cloning-your-fork">
<span id="cloning"></span><h3>Cloning Your Fork<a class="headerlink" href="#cloning-your-fork" title="Permalink to this heading"></a></h3>
<p>After you have created your fork, clone it by running the following command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><style type="text/css">
span.prompt1:before {
  content: "$ ";
}
</style><span class="prompt1">git<span class="w"> </span>clone<span class="w"> </span>https://github.com/mygithubaccount/ceph</span>
</pre></div></div><p>You must fork the Ceph repository before you clone it.  If you fail to fork,
you cannot open a <a class="reference external" href="https://docs.github.com/en/free-pro-team&#64;latest/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request">GitHub pull request</a>.</p>
<p>For more information on using GitHub, refer to <a class="reference external" href="https://help.github.com/">GitHub Help</a>.</p>
</section>
<section id="configuring-your-local-environment">
<h3>Configuring Your Local Environment<a class="headerlink" href="#configuring-your-local-environment" title="Permalink to this heading"></a></h3>
<p>The commands in this section configure your local git environment so that it
generates <code class="docutils literal notranslate"><span class="pre">Signed-off-by:</span></code> tags. These commands also set up your local
environment so that it can stay synchronized with the upstream repository.</p>
<p>The commands in this section are necessary only during the initial setup of
your local working copy. This means that these commands are necessary only the
first time that you are working with the Ceph repository. They are, however,
unavoidable, and if you fail to run them then you will not be able to work on
the Ceph repository..</p>
<ol class="arabic">
<li><p>Configure your local git environment with your name and email address.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>These commands will work only from within the <code class="docutils literal notranslate"><span class="pre">ceph/</span></code> directory
that was created when you cloned your fork.</p>
</div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>config<span class="w"> </span>user.name<span class="w"> </span><span class="s2">&quot;FIRST_NAME LAST_NAME&quot;</span></span>
<span class="prompt1">git<span class="w"> </span>config<span class="w"> </span>user.email<span class="w"> </span><span class="s2">&quot;MY_NAME@example.com&quot;</span></span>
</pre></div></div></li>
<li><p>Add the upstream repo as a “remote” and fetch it:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>remote<span class="w"> </span>add<span class="w"> </span>ceph<span class="w"> </span>https://github.com/ceph/ceph.git</span>
<span class="prompt1">git<span class="w"> </span>fetch<span class="w"> </span>ceph</span>
</pre></div></div><p>These commands fetch all the branches and commits from <code class="docutils literal notranslate"><span class="pre">ceph/ceph.git</span></code> to
the local git repo as <code class="docutils literal notranslate"><span class="pre">remotes/ceph/$BRANCH_NAME</span></code> and can be referenced as
<code class="docutils literal notranslate"><span class="pre">ceph/$BRANCH_NAME</span></code> in local git commands.</p>
</li>
</ol>
</section>
</section>
<section id="fixing-the-bug">
<h2>Fixing the Bug<a class="headerlink" href="#fixing-the-bug" title="Permalink to this heading"></a></h2>
<section id="synchronizing-local-main-with-upstream-main">
<span id="synchronizing"></span><h3>Synchronizing Local Main with Upstream Main<a class="headerlink" href="#synchronizing-local-main-with-upstream-main" title="Permalink to this heading"></a></h3>
<p>In your local working copy, there is a copy of the <code class="docutils literal notranslate"><span class="pre">main</span></code> branch in
<code class="docutils literal notranslate"><span class="pre">remotes/origin/main</span></code>. This is called “local main”. This copy of the
main branch (<a class="reference external" href="https://github.com/your_github_id/ceph.git">https://github.com/your_github_id/ceph.git</a>) is “frozen in time”
at the moment that you cloned it, but the upstream repo
(<a class="reference external" href="https://github.com/ceph/ceph.git">https://github.com/ceph/ceph.git</a>, typically abbreviated to <code class="docutils literal notranslate"><span class="pre">ceph/ceph.git</span></code>)
that it was forked from is not frozen in time: the upstream repo is still being
updated by other contributors.</p>
<p>Because upstream main is continually receiving updates from other contributors,
over time your fork will drift farther and farther from the state of the
upstream repository as it was when you cloned it.</p>
<p>Keep your fork’s <code class="docutils literal notranslate"><span class="pre">main</span></code> branch synchronized with upstream main to reduce
drift between your fork’s main branch and the upstream main branch.</p>
<p>Here are the commands for keeping your fork synchronized with the
upstream repository:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>fetch<span class="w"> </span>ceph</span>
<span class="prompt1">git<span class="w"> </span>checkout<span class="w"> </span>main</span>
<span class="prompt1">git<span class="w"> </span>reset<span class="w"> </span>--hard<span class="w"> </span>ceph/main</span>
<span class="prompt1">git<span class="w"> </span>push<span class="w"> </span>-u<span class="w"> </span>origin<span class="w"> </span>main</span>
</pre></div></div><p>Follow this procedure often to keep your local <code class="docutils literal notranslate"><span class="pre">main</span></code> in sync with upstream
<code class="docutils literal notranslate"><span class="pre">main</span></code>.</p>
<p>If the command <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">status</span></code> returns a line that reads “Untracked files”, see
<a class="reference internal" href="../../../install/clone-source/#update-submodules"><span class="std std-ref">the procedure on updating submodules</span></a>.</p>
</section>
<section id="creating-a-bugfix-branch">
<span id="bugfix-branch"></span><h3>Creating a Bugfix branch<a class="headerlink" href="#creating-a-bugfix-branch" title="Permalink to this heading"></a></h3>
<p>Create a branch for your bugfix:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>checkout<span class="w"> </span>main</span>
<span class="prompt1">git<span class="w"> </span>checkout<span class="w"> </span>-b<span class="w"> </span>fix_1</span>
<span class="prompt1">git<span class="w"> </span>push<span class="w"> </span>-u<span class="w"> </span>origin<span class="w"> </span>fix_1</span>
</pre></div></div><p>The first command (<code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">checkout</span> <span class="pre">main</span></code>) makes sure that the bugfix branch
“fix_1” is created from the most recent state of the main branch of the
upstream repository.</p>
<p>The second command (<code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">checkout</span> <span class="pre">-b</span> <span class="pre">fix_1</span></code>) creates a “bugfix branch” called
“fix_1” in your local working copy of the repository. The changes that you make
in order to fix the bug will be committed to this branch.</p>
<p>The third command (<code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">push</span> <span class="pre">-u</span> <span class="pre">origin</span> <span class="pre">fix_1</span></code>) pushes the bugfix branch from
your local working repository to your fork of the upstream repository.</p>
</section>
<section id="fixing-the-bug-in-the-local-working-copy">
<span id="fixing-bug-locally"></span><h3>Fixing the bug in the local working copy<a class="headerlink" href="#fixing-the-bug-in-the-local-working-copy" title="Permalink to this heading"></a></h3>
<ol class="arabic">
<li><p><strong>Updating the tracker</strong></p>
<p>In the <a class="reference external" href="https://tracker.ceph.com">Ceph issue tracker</a>, change the status
of the tracker issue to “In progress”.  This communicates to other Ceph
contributors that you have begun working on a fix, which helps to avoid
duplication of effort. If you don’t have permission to change that field,
just comment that you are working on the issue.</p>
</li>
<li><p><strong>Fixing the bug itself</strong></p>
<p>This guide cannot tell you how to fix the bug that you have chosen to fix.
This guide assumes that you have identified an area that required
improvement, and that you know how to make that improvement.</p>
<p>It might be that your fix is simple and that it requires only minimal
testing. But that’s unlikely unless you’re updating only documentation. It
is more likely that the process of fixing your bug will require several
rounds of testing. The testing process is likely to be iterative and will
involve trial, error, skill, and patience.</p>
<p>For a detailed discussion of the tools available for validating bugfixes,
see <a class="reference internal" href="../tests-unit-tests/#dev-testing-unit-tests"><span class="std std-ref">the sections that discuss testing</span></a>.</p>
</li>
</ol>
</section>
<section id="pushing-the-fix-to-your-fork">
<h3>Pushing the Fix to Your Fork<a class="headerlink" href="#pushing-the-fix-to-your-fork" title="Permalink to this heading"></a></h3>
<p>You have finished work on the bugfix. You have tested the bugfix, and you
believe that it works.</p>
<ol class="arabic">
<li><p>Commit the changes to your local working copy.</p>
<p>Commit the changes to the <code class="docutils literal notranslate"><span class="pre">fix_1</span></code> branch of your local working copy by
using the <code class="docutils literal notranslate"><span class="pre">--signoff</span></code> option (here represented as the <code class="docutils literal notranslate"><span class="pre">s</span></code> portion of the
<code class="docutils literal notranslate"><span class="pre">-as</span></code> flag):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>commit<span class="w"> </span>-as</span>
</pre></div></div></li>
<li id="push-changes"><p>Push the changes to your fork:</p>
<p>Push the changes from the <code class="docutils literal notranslate"><span class="pre">fix_1</span></code> branch of your local working copy to the
<code class="docutils literal notranslate"><span class="pre">fix_1</span></code> branch of your fork of the upstream repository:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>push<span class="w"> </span>origin<span class="w"> </span>fix_1</span>
</pre></div></div><div class="admonition note">
<p class="admonition-title">Note</p>
<p>In the command <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">push</span> <span class="pre">origin</span> <span class="pre">fix_1</span></code>, <code class="docutils literal notranslate"><span class="pre">origin</span></code> is the name of your
fork of the upstream Ceph repository, and can be thought of as a nickname
for <code class="docutils literal notranslate"><span class="pre">git&#64;github.com:username/ceph.git</span></code>, where <code class="docutils literal notranslate"><span class="pre">username</span></code> is your
GitHub username.</p>
<p>It is possible that <code class="docutils literal notranslate"><span class="pre">origin</span></code> is not the name of your fork. Discover the
name of your fork by running <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">remote</span> <span class="pre">-v</span></code>, as shown here:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>remote<span class="w"> </span>-v
ceph<span class="w">   </span>https://github.com/ceph/ceph.git<span class="w"> </span><span class="o">(</span>fetch<span class="o">)</span>
ceph<span class="w">   </span>https://github.com/ceph/ceph.git<span class="w"> </span><span class="o">(</span>push<span class="o">)</span>
origin<span class="w"> </span>git@github.com:username/ceph.git<span class="w"> </span><span class="o">(</span>fetch<span class="o">)</span>
origin<span class="w"> </span>git@github.com:username/ceph.git<span class="w"> </span><span class="o">(</span>push<span class="o">)</span>
</pre></div>
</div>
<p>The line:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">origin</span> <span class="n">git</span><span class="nd">@github</span><span class="o">.</span><span class="n">com</span><span class="p">:</span><span class="n">username</span><span class="o">/</span><span class="n">ceph</span><span class="o">.</span><span class="n">git</span> <span class="p">(</span><span class="n">fetch</span><span class="p">)</span>
</pre></div>
</div>
<p>and the line:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">origin</span> <span class="n">git</span><span class="nd">@github</span><span class="o">.</span><span class="n">com</span><span class="p">:</span><span class="n">username</span><span class="o">/</span><span class="n">ceph</span><span class="o">.</span><span class="n">git</span> <span class="p">(</span><span class="n">push</span><span class="p">)</span>
</pre></div>
</div>
<p>provide the information that <code class="docutils literal notranslate"><span class="pre">origin</span></code> is the name of your fork of the
Ceph repository.</p>
</div>
</li>
</ol>
</section>
</section>
<section id="opening-a-github-pull-request">
<h2>Opening a GitHub pull request<a class="headerlink" href="#opening-a-github-pull-request" title="Permalink to this heading"></a></h2>
<p>After you have pushed the bugfix to your fork, open a GitHub pull request
(PR). This makes your bugfix visible to the community of Ceph contributors.
They will review it. They may perform additional testing on your bugfix, and
they might request changes to the bugfix.</p>
<p>Be prepared to receive suggestions and constructive criticism in the form of
comments within the PR.</p>
<p>If you don’t know how to create and manage pull requests, read <a class="reference external" href="https://help.github.com/articles/using-pull-requests/">this GitHub
pull request tutorial</a>.</p>
<p>To learn what constitutes a “good” pull request, see
the <a class="reference external" href="https://wiki.openstack.org/wiki/GitCommitMessages">Git Commit Good Practice</a> article at the <a class="reference external" href="https://wiki.openstack.org/wiki/Main_Page">OpenStack Project Wiki</a>.</p>
<p>See also Ceph’s own <a class="reference external" href="https://github.com/ceph/ceph/blob/main/SubmittingPatches.rst">Submitting Patches</a> document.</p>
<p>After your pull request (PR) has been opened, update the <a class="reference internal" href="../issue-tracker/#issue-tracker"><span class="std std-ref">问题跟踪</span></a>
by adding a comment directing other contributors to your PR. The comment can be
as simple as this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>*PR*: https://github.com/ceph/ceph/pull/$NUMBER_OF_YOUR_PULL_REQUEST
</pre></div>
</div>
</section>
<section id="understanding-automated-pr-validation">
<h2>Understanding Automated PR validation<a class="headerlink" href="#understanding-automated-pr-validation" title="Permalink to this heading"></a></h2>
<p>When you create or update your PR, the Ceph project’s <a class="reference external" href="https://en.wikipedia.org/wiki/Continuous_integration">Continuous Integration
(CI)</a> infrastructure
automatically tests it. Here are just some of the automated tests that are
performed on your PR:</p>
<ol class="arabic simple">
<li><p>a test to check that the commits are properly signed (see
<a class="reference internal" href="../essentials/#submitting-patches"><span class="std std-ref">补丁的提交</span></a>):</p></li>
<li><p>a test to check that the documentation builds</p></li>
<li><p>a test to check that the submodules are unmodified</p></li>
<li><p>a test to check that the API is in order</p></li>
<li><p>a <a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> test</p></li>
</ol>
<p>Additional tests may be run, depending which files your PR modifies.</p>
<p>The <a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> test builds the PR and runs it through a
battery of tests. These tests run on servers that are operated by the Ceph
Continuous Integration (CI) team. When the tests have completed their run, the
result is shown on GitHub in the pull request itself.</p>
<p>Test your modifications before you open a PR.  Refer to <a class="reference internal" href="../tests-unit-tests/#dev-testing-unit-tests"><span class="std std-ref">the sections on
testing</span></a> for details.</p>
<section id="notes-on-pr-make-check-test">
<h3>Notes on PR make check test<a class="headerlink" href="#notes-on-pr-make-check-test" title="Permalink to this heading"></a></h3>
<p>The GitHub <a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> test is driven by a Jenkins instance.</p>
<p>Jenkins merges your PR branch into the latest version of the base branch before
it starts any tests. This means that you don’t have to rebase the PR in order
to pick up any fixes.</p>
<p>You can trigger PR tests at any time by adding a comment to the PR - the
comment should contain the string “test this please”. Since a human who is
subscribed to the PR might interpret that as a request for him or her to test
the PR, you must address Jenkins directly. For example, write “jenkins retest
this please”. If you need to run only one of the tests, you can request it with
a command like “jenkins test signed”. A list of these requests is automatically
added to the end of each new PR’s description, so check there to find the
single test you need.</p>
<p>If there is a build failure and you aren’t sure what caused it, check the
<a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> log. To access the make check log, click the
“details” (next to the <a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> test in the PR) link to
enter the Jenkins web GUI. Then click “Console Output” (on the left).</p>
<p>Jenkins is configured to search logs for strings that are known to have been
associated with <a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> failures in the past. However,
there is no guarantee that these known strings are associated with any given
<a class="reference internal" href="../tests-unit-tests/#make-check"><span class="std std-ref">make check</span></a> failure. You’ll have to read through the log to
determine the cause of your specific failure.</p>
</section>
</section>
<section id="integration-tests-aka-ceph-qa-suite">
<h2>Integration tests AKA ceph-qa-suite<a class="headerlink" href="#integration-tests-aka-ceph-qa-suite" title="Permalink to this heading"></a></h2>
<p>It may be necessary to test your fix on real Ceph clusters that run on physical
or virtual hardware. Tests designed for this purpose reside in the <a class="reference external" href="https://github.com/ceph/ceph/tree/main/qa/">ceph/qa
sub-directory</a> and are run via the <a class="reference external" href="https://github.com/ceph/teuthology">teuthology framework</a>.</p>
<p>The Ceph community has access to the <a class="reference external" href="https://wiki.sepia.ceph.com/doku.php">Sepia lab</a> where <a class="reference external" href="../testing_integration_tests/tests-integration-testing-teuthology-intro">integration tests</a> can be run
on physical hardware.</p>
<p>Other contributors might add tags like <code class="docutils literal notranslate"><span class="pre">needs-qa</span></code> to your PR. This allows PRs
to be merged into a single branch and then efficiently tested together.
Teuthology test suites can take hours (and, in some cases, days) to
complete, so batching tests reduces contention for resources and saves
time.</p>
<p>If your code change has any effect on upgrades, add the
<code class="docutils literal notranslate"><span class="pre">needs-upgrade-testing</span></code> label. This indicates that an upgrade testing suite
should be scheduled.</p>
<p>To request access to the Sepia lab, start <a class="reference external" href="https://wiki.sepia.ceph.com/doku.php?id=vpnaccess">here</a>.</p>
<p>Integration testing is discussed in more detail in the <a class="reference external" href="../testing_integration_tests/tests-integration-testing-teuthology-intro">integration
tests</a> chapter.</p>
</section>
<section id="code-review">
<h2>Code review<a class="headerlink" href="#code-review" title="Permalink to this heading"></a></h2>
<p>After your bugfix has been thoroughly tested--and sometimeseven during the
testing--it will be subjected to code review by other developers. This
typically takes the form of comments in the PR itself, but can be supplemented
by discussions on <a class="reference internal" href="../essentials/#irc"><span class="std std-ref">IRC</span></a>, or on <a class="reference internal" href="../essentials/#ceph-slack"><span class="std std-ref">Slack</span></a> or on the
<a class="reference internal" href="../essentials/#mailing-list"><span class="std std-ref">邮件列表</span></a>.</p>
</section>
<section id="amending-your-pr">
<h2>Amending your PR<a class="headerlink" href="#amending-your-pr" title="Permalink to this heading"></a></h2>
<p>While your PR is going through testing and <a class="reference internal" href="#code-review">Code Review</a>, you can
modify it at any time by editing files in your local branch.</p>
<p>After updates are committed locally (to the <code class="docutils literal notranslate"><span class="pre">fix_1</span></code> branch in our
example), they must be pushed to GitHub in order to appear in the PR.</p>
<p>Modifying the PR is done by adding commits to the <code class="docutils literal notranslate"><span class="pre">fix_1</span></code> branch upon which
it is based, often followed by rebasing to modify the branch’s git history. See
<a class="reference external" href="https://www.atlassian.com/git/tutorials/rewriting-history">this tutorial</a>
for an introduction to rebasing. When you are done with your modifications, you
will need to force push your branch by running a command of the following form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>push<span class="w"> </span>--force<span class="w"> </span>origin<span class="w"> </span>fix_1</span>
</pre></div></div><p>Why do we take these extra steps instead of simply adding additional commits to
the PR? It is best practice for a PR to consist of a single commit; this makes
it possible to maintain a clean history, it simplifies peer review of your
changes, and it makes merging your PR easier. In the unlikely event that your
PR has to be reverted, having a single commit associated with that PR makes the
procession of reversion easier.</p>
</section>
<section id="merging">
<h2>Merging<a class="headerlink" href="#merging" title="Permalink to this heading"></a></h2>
<p>The bugfix process completes when a project lead merges your PR.</p>
<p>When this happens, it is a signal for you (or the lead who merged the PR)
to change the <a class="reference internal" href="../issue-tracker/#issue-tracker"><span class="std std-ref">问题跟踪</span></a> status to “Resolved”. Some issues may be
flagged for backporting, in which case the status should be changed to
“Pending Backport” (see the <a class="reference internal" href="../essentials/#backporting"><span class="std std-ref">补丁移植（ Backporting ）</span></a> chapter for details).</p>
<p>See <a class="reference internal" href="../merging/#merging"><span class="std std-ref">合并提交：范围和节奏</span></a> for more information on merging.</p>
<section id="proper-merge-commit-format">
<h3>Proper Merge Commit Format<a class="headerlink" href="#proper-merge-commit-format" title="Permalink to this heading"></a></h3>
<p>This is the most basic form of a merge commit:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">doc</span><span class="o">/</span><span class="n">component</span><span class="p">:</span> <span class="n">title</span> <span class="n">of</span> <span class="n">the</span> <span class="n">commit</span>

<span class="n">Reviewed</span><span class="o">-</span><span class="n">by</span><span class="p">:</span> <span class="n">Reviewer</span> <span class="n">Name</span> <span class="o">&lt;</span><span class="n">rname</span><span class="nd">@example</span><span class="o">.</span><span class="n">com</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>This consists of two parts:</p>
<ol class="arabic simple">
<li><p>The title of the commit to be merged.</p></li>
<li><p>The name and email address of the reviewer. Enclose the reviewer’s email
address in angle brackets.</p></li>
</ol>
</section>
<section id="using-a-browser-extension-to-auto-fill-the-merge-message">
<h3>Using a browser extension to auto-fill the merge message<a class="headerlink" href="#using-a-browser-extension-to-auto-fill-the-merge-message" title="Permalink to this heading"></a></h3>
<p>If you use a browser to merge GitHub PRs, the easiest way to fill in
the merge message is with the <a class="reference external" href="https://github.com/tspmelo/ceph-github-helper">“Ceph GitHub Helper Extension”</a> (available for <a class="reference external" href="https://chrome.google.com/webstore/detail/ceph-github-helper/ikpfebikkeabmdnccbimlomheocpgkmn">Chrome</a>
and <a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/ceph-github-helper/">Firefox</a>).</p>
<p>After enabling this extension, if you go to a GitHub PR page, a vertical helper
will be displayed at the top-right corner. If you click on the user silhouette
button the merge message input will be automatically populated.</p>
</section>
<section id="using-githubmap-to-find-a-reviewer-s-email-address">
<h3>Using .githubmap to Find a Reviewer’s Email Address<a class="headerlink" href="#using-githubmap-to-find-a-reviewer-s-email-address" title="Permalink to this heading"></a></h3>
<p>If you cannot find the email address of the reviewer on his or her GitHub page,
you can look it up in the <code class="docutils literal notranslate"><span class="pre">.githubmap</span></code> file, which can be found in the
repository at <code class="docutils literal notranslate"><span class="pre">/ceph/.githubmap</span></code>.</p>
</section>
<section id="using-git-log-to-find-a-reviewer-s-email-address">
<h3>Using “git log” to find a Reviewer’s Email Address<a class="headerlink" href="#using-git-log-to-find-a-reviewer-s-email-address" title="Permalink to this heading"></a></h3>
<p>If you cannot find a reviewer’s email address by using the above methods, you
can search the git log for their email address. Reviewers are likely to have
committed something before. If they have made previous contributions, the git
log will probably contain their email address.</p>
<p>Use the following command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><style type="text/css">
span.prompt2:before {
  content: "[branch-under-review]$ ";
}
</style><span class="prompt2">git<span class="w"> </span>log</span>
</pre></div></div></section>
<section id="using-ptl-tool-to-generate-merge-commits">
<h3>Using ptl-tool to Generate Merge Commits<a class="headerlink" href="#using-ptl-tool-to-generate-merge-commits" title="Permalink to this heading"></a></h3>
<p>Another method of generating merge commits involves using Patrick Donnelly’s
<code class="docutils literal notranslate"><span class="pre">ptl-tool</span></code> to pull commits. This tool can be found at
<code class="docutils literal notranslate"><span class="pre">/ceph/src/script/ptl-tool.py</span></code>.  Merge commits that have been generated by the
<code class="docutils literal notranslate"><span class="pre">ptl-tool</span></code> have the following form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Merge</span> <span class="n">PR</span> <span class="c1">#36257 into main</span>
<span class="o">*</span> <span class="n">refs</span><span class="o">/</span><span class="n">pull</span><span class="o">/</span><span class="mi">36257</span><span class="o">/</span><span class="n">head</span><span class="p">:</span>
        <span class="n">client</span><span class="p">:</span> <span class="n">move</span> <span class="n">client_lock</span> <span class="n">to</span> <span class="n">_unmount</span><span class="p">()</span>
        <span class="n">client</span><span class="p">:</span> <span class="n">add</span> <span class="n">timer_lock</span> <span class="n">support</span>
<span class="n">Reviewed</span><span class="o">-</span><span class="n">by</span><span class="p">:</span> <span class="n">Patrick</span> <span class="n">Donnelly</span> <span class="o">&lt;</span><span class="n">pdonnell</span><span class="nd">@redhat</span><span class="o">.</span><span class="n">com</span><span class="o">&gt;</span>
</pre></div>
</div>
</section>
</section>
<section id="miscellaneous">
<h2>Miscellaneous<a class="headerlink" href="#miscellaneous" title="Permalink to this heading"></a></h2>
<section id="set-upstream">
<h3>--set-upstream<a class="headerlink" href="#set-upstream" title="Permalink to this heading"></a></h3>
<p>If you forget to include the <code class="docutils literal notranslate"><span class="pre">--set-upstream</span> <span class="pre">origin</span> <span class="pre">x</span></code> option in your <code class="docutils literal notranslate"><span class="pre">git</span>
<span class="pre">push</span></code> command, you will see the following error message:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">fatal</span><span class="p">:</span> <span class="n">The</span> <span class="n">current</span> <span class="n">branch</span> <span class="p">{</span><span class="n">x</span><span class="p">}</span> <span class="n">has</span> <span class="n">no</span> <span class="n">upstream</span> <span class="n">branch</span><span class="o">.</span>
<span class="n">To</span> <span class="n">push</span> <span class="n">the</span> <span class="n">current</span> <span class="n">branch</span> <span class="ow">and</span> <span class="nb">set</span> <span class="n">the</span> <span class="n">remote</span> <span class="k">as</span> <span class="n">upstream</span><span class="p">,</span> <span class="n">use</span>
   <span class="n">git</span> <span class="n">push</span> <span class="o">--</span><span class="nb">set</span><span class="o">-</span><span class="n">upstream</span> <span class="n">origin</span> <span class="p">{</span><span class="n">x</span><span class="p">}</span>
</pre></div>
</div>
<p>To set up git to automatically create the upstream branch that corresponds to
the branch in your local working copy (without having to add the option
<code class="docutils literal notranslate"><span class="pre">--set-upstream</span> <span class="pre">origin</span> <span class="pre">x</span></code> every time), run this command from within the
<code class="docutils literal notranslate"><span class="pre">ceph/</span></code> directory:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>push.autoSetupRemote<span class="w"> </span><span class="nb">true</span></span>
</pre></div></div></section>
<section id="deleting-a-branch-locally">
<h3>Deleting a Branch Locally<a class="headerlink" href="#deleting-a-branch-locally" title="Permalink to this heading"></a></h3>
<p>To delete the branch named <code class="docutils literal notranslate"><span class="pre">localBranchName</span></code> from the local working copy, run
a command of this form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>branch<span class="w"> </span>-d<span class="w"> </span>localBranchName</span>
</pre></div></div></section>
<section id="deleting-a-branch-remotely">
<h3>Deleting a Branch Remotely<a class="headerlink" href="#deleting-a-branch-remotely" title="Permalink to this heading"></a></h3>
<p>To delete the branch named <code class="docutils literal notranslate"><span class="pre">remoteBranchName</span></code> from the remote upstream branch
(which is also your fork of <code class="docutils literal notranslate"><span class="pre">ceph/ceph</span></code>, as described in <a class="reference internal" href="#forking"><span class="std std-ref">Creating a Fork of the Ceph Repository</span></a>), run
a command of the following form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>push<span class="w"> </span>origin<span class="w"> </span>--delete<span class="w"> </span>remoteBranchName</span>
</pre></div></div></section>
<section id="searching-a-file-longitudinally-for-a-string">
<h3>Searching a File Longitudinally for a String<a class="headerlink" href="#searching-a-file-longitudinally-for-a-string" title="Permalink to this heading"></a></h3>
<p>To search for the commit that introduced a given string (in this example, that
string is <code class="docutils literal notranslate"><span class="pre">foo</span></code>) into a given file (in this example, that file is
<code class="docutils literal notranslate"><span class="pre">file.rst</span></code>), use the <code class="docutils literal notranslate"><span class="pre">-S</span> <span class="pre">&lt;string&gt;</span></code> option. Run a command of the following
form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span class="prompt1">git<span class="w"> </span>log<span class="w"> </span>-S<span class="w"> </span><span class="s1">&#39;foo&#39;</span><span class="w"> </span>file.rst</span>
</pre></div></div></section>
</section>
</section>



<div id="support-the-ceph-foundation" class="admonition note">
  <p class="first admonition-title">Brought to you by the Ceph Foundation</p>
  <p class="last">The Ceph Documentation is a community resource funded and hosted by the non-profit <a href="https://ceph.io/en/foundation/">Ceph Foundation</a>. If you would like to support this and our other efforts, please consider <a href="https://ceph.io/en/foundation/join/">joining now</a>.</p>
</div>


           </div>
           
          </div>
          <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
        <a href="../issue-tracker/" class="btn btn-neutral float-left" title="问题跟踪" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
        <a href="../tests-unit-tests/" class="btn btn-neutral float-right" title="测试 - 单元测试" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
    </div>

  <hr/>

  <div role="contentinfo">
    <p>&#169; Copyright 2016, Ceph authors and contributors. Licensed under Creative Commons Attribution Share Alike 3.0 (CC-BY-SA-3.0).</p>
  </div>

   

</footer>
        </div>
      </div>

    </section>

  </div>
  

  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script>

  
  
    
   

</body>
</html>